package com.hllxd.hism.star.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bj58.zp.cdata.framework.rpc.client.basic.RpcInvoker;
import com.bj58.zp.cdata.framework.rpc.client.basic.RpcReqData;
import com.bj58.zp.cdata.framework.rpc.client.basic.RpcResData;
import com.bj58.zp.cdata.framework.rpc.client.config.client.ServiceProperties;
import com.bj58.zp.cdata.framework.rpc.client.utils.OkHttpUtil;
import com.hllxd.hism.star.util.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * @author lixiyong
 * @date 20190909
 * @description SVC是Switching Virtual Circuit的缩写，意思是交换虚拟电路
 */
@Slf4j
@RestController
@RequestMapping("/star/api")
public class SvcController {

    @Autowired
    private RpcInvoker rpcInvoker;

    @Data
    public static class SvcDto {
        public Object params;
    }

    /**
     * 通用执行接口
     */
    @RequestMapping(value = "**/*.do", method = RequestMethod.POST)
    @ResponseBody
    public Object request(@RequestBody String dto, HttpServletRequest request) {
        String uri = request.getRequestURI();
        log.info("param:{}, {}", uri, dto);
        ServicePath sp = initServicePath(uri);
        if (sp == null) {
            log.warn("uri is invalid. {}", uri);
            return ResultUtils.errorResult("1011003", "uri is invalid.");
        }
//        log.info("isSafeMode:{}.", ParserConfig.getGlobalInstance().isSafeMode());
        String traceID = "", userID = "";
        try {
            ConsoleContext context = ThreadLocalManager.getConsoleContext();
            if (context != null) {
                traceID = context.getTraceId();
                userID = context.getUserID();
            } else {
                userID = "999999";
                traceID = getTraceID();
            }
            log.info("request userID: {}, traceID:{}, uri: {}", userID, traceID, uri);
            SyslogManager.product(traceID, userID, sp.service, sp.path);
            RpcReqData reqData = buildRpcReqData(traceID, userID, sp.path, dto);
            RpcResData<String> rpcResData = rpcInvoker.invoke(sp.service, reqData);
            if (rpcResData == null) {
                return ResultUtils.errorResult("1011001", "Request Service Failed.");
            }
            return ResultUtils.result(rpcResData.getCode(), rpcResData.getMessage(), JSON.parse(rpcResData.getData()));
        } catch (Exception e) {
            log.warn("Exception: {}, {}, {}", uri, dto, e, e);
            return ResultUtils.errorResult("1011002", "Exception:" + e);
        }
    }

    @Autowired
    private ServiceProperties serviceProperties;

    /**
     * 调用外部接口
     */
    @RequestMapping(value = "**/*", method = RequestMethod.POST)
    @ResponseBody
    public Object requestOut(@RequestBody String dto, HttpServletRequest request) {
        String uri = request.getRequestURI();
        log.info("param:{}, {}", uri, dto);
        ServicePath sp = initServicePath(uri);
        if (sp == null) {
            log.warn("uri is invalid. {}", uri);
            return ResultUtils.errorResult("1011003", "uri is invalid.");
        }
        String traceID = "", userID = "";
        try {
            ConsoleContext context = ThreadLocalManager.getConsoleContext();
            if (context != null) {
                traceID = context.getTraceId();
                userID = context.getUserID();
            } else {
                userID = "999999";
                traceID = getTraceID();
            }
            log.info("request userID: {}, traceID:{}, uri: {}", userID, traceID, uri);
//			RpcReqData reqData = buildRpcReqData(traceID, userID, sp.path, dto);
//			RpcResData<String> rpcResData = rpcInvoker.invoke(sp.service, reqData);

            Map<String, String> hosts = serviceProperties.getHosts();
            String realHost = hosts.get(sp.service);
            String realTarget = realHost + sp.path;

            String result = OkHttpUtil.httpPost(dto, realTarget, 60000L);
            log.info("result: {}, traceId:{}", result, traceID);
            if (result == null) {
                return ResultUtils.errorResult("1011001", "Request Service Failed.");
            }
            JSONObject resJson = JSONObject.parseObject(result);
            return ResultUtils.result(resJson.get("code").toString(), resJson.get("message").toString(), resJson.get("data"));
        } catch (Exception e) {
            log.warn("Exception: {}, {}, {}", uri, dto, e, e);
            return ResultUtils.errorResult("1011002", "Exception:" + e);
        }
    }

    static class ServicePath {
        public String service;
        public String path;

        public static ServicePath build(String service, String path) {
            ServicePath thiz = new ServicePath();
            thiz.service = service;
            thiz.path = path;
            return thiz;
        }
    }

    // "/hllxd/api/basic/v1/user/userInfo.do"
    private static ServicePath initServicePath(String uri) {
        try {
            String[] items = uri.split("/");
            StringBuilder sb = new StringBuilder();
            for (int i = 4; i < items.length; ++i) {
                sb.append("/").append(items[i]);
            }
            return ServicePath.build(items[3], sb.toString());
        } catch (Exception e) {
            log.warn("Exception: {}.", e.toString());
            return null;
        }
    }

    private static RpcReqData buildRpcReqData(String traceID, String userID, String path, String params) {
        RpcReqData thiz = new RpcReqData();
        thiz.setTraceID(traceID);
        thiz.setUserID(userID);
        thiz.setPath(path);
        thiz.setData(JSON.parse(params));
        return thiz;
    }

    private String getTraceID() {
        String traceID;
        ConsoleContext context = ThreadLocalManager.getConsoleContext();
        if (context != null) {
            traceID = context.getTraceId();
        } else {
            traceID = TraceUtil.newTraceId();
        }
        return traceID;
    }
}
